-- card: 15753 from stack: in.3 -- bmap block id: 0 -- flags: 4000 -- background id: 3241 -- name: ModalDialog ----- HyperTalk script ----- on Install get ChooseTargetStack() InstallResource XFCN,ModalDialog,it end Install -- part 3 (field) -- low flags: 81 -- high flags: 2007 -- rect: left=12 top=26 right=298 bottom=491 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 22 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: Source -- part 5 (button) -- low flags: 00 -- high flags: A003 -- rect: left=80 top=300 right=322 bottom=180 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 0 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: Try It ----- HyperTalk script ----- on mouseUp DoSearch -- the handler for the DoSearch message is in the script of -- this stack end mouseUp -- part 10 (button) -- low flags: 00 -- high flags: A003 -- rect: left=299 top=300 right=322 bottom=438 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 0 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: Show Pascal Source ----- HyperTalk script ----- on mouseUp set the visible of card field 1 to not the visible of card field 1 if the visible of card field 1 is true then set the name of me to "Hide Pascal Source" else set the name of me to "Show Pascal Source" end mouseUp -- part contents for background part 16 ----- text ----- MODALDIALOG XFCN version 1.0.3 Kevin Calhoun ModalDialog displays a dialog box created by any resource generator or editor, such as ResEdit. It permits the user to interact with the dialog in the standard Macintosh fashion and, once the user dismisses the dialog, returns information about the contents of all the editable text items and the state of all the check boxes and radio buttons at the time the dialog was dismissed. INVOKING MODALDIALOG get ModalDialog("DLOGName",,,,) returns if the user presses the default button: a multi-lined expression, explained below, describing the contents of the dialog box if the user presses the cancel button: "Cancel" if an error occurs: "Error " followed by an error code WHAT YOU PASS TO MODALDIALOG You tell ModalDialog which dialog to display by passing the name of its DLOG resource in the first parameter. For example, ModalDialog("ask") brings up HyperCard's ask dialog. You should enclose this name in quotation marks. The rest of the parameters are optional. The second parameter, containerName, is the name of a HyperTalk container. Before calling ModalDialog, you can store a multi-lined expression in this container that will determine the following properties of the dialog: the text of text items, the initial state of check boxes and radio buttons, the grouping of radio buttons, and the default and cancel buttons. The container should include one line for each dialog item in the DITL resource--ModalDialog matches each dialog item with the corresponding line in the container. If there is no second parameter, or if it is empty, then the dialog will appear in the default state: the text items will contain the text specified by the DITL, check boxes and radio buttons will be turned off, all radio buttons will be grouped together, the default button will be the first button in the DITL, and the cancel button will be the second button in the DITL. The next few paragraphs explain how to override this default behavior. If the dialog item is a button control, ModalDialog looks in its corresponding line in containerName for two items: defaultOrCancel,Name If defaultOrCancel is "Default", the button becomes the default button (the one that's pushed when the user presses the return or enter key) and the familiar bold outline will be drawn around it. If defaultOrCancel is "Cancel", the button becomes the cancel button (the one that's pushed when the user presses the escape key, command-period, or command-Q). If more than one button is designated the default button, the last of these in the list becomes the actual default button. The same rule applies for multiple buttons designated the cancel button. If Name is not empty, then the title of the button will be set to it. If the dialog item is a check box, ModalDialog looks in its corresponding line in containerName for two items: onOrOff,Name If onOrOff is "On", the check box will be checked when it first appears. If Name is not empty, the title of the check box will be set to it. If the dialog item is a radio button, ModalDialog looks in its corresponding line in containerName for three items: onOrOff,group,Name If onOrOff is "On", the radio button will be on when it first appears. Group is a number that tells ModalDialog which radio buttons should be turned off when the user turns the radio button on. When the user clicks a radio button, ModalDialog does nothing if the radio button is already on; if it's off, every other radio button with the same group number is turned off before it's turned on. If group is empty, the radio button is assigned to group number 0. (Note: ModalDialog doesn't check whether you turn more than one radio button on within the same group. If you do this, the radio buttons in that group will not behave normally.) If Name is not empty, the title of the radio button will be set to it. If the dialog item is an editable text item, ModalDialog looks in its corresponding line in containerName for two items: text,select If text is not empty, the text of the dialog item will be set to it. If select is "Select", the text of the item will be selected. If more than one text item is designated the selected item, the last of these in the list will actually be selected when the dialog appears. If none of the dialog items is selected in this fashion, the first edit item in the list will be selected when the dialog appears. If the dialog item is a static text item, ModalDialog will set the text of the dialog item to the line in containerName that corresponds to it, unless that line is empty. If the dialog item is an icon item, a picture item, a user item, or a control defined by a resource template in a resource file, ModalDialog ignores the line in containerName that corresponds to it. The third parameter, dialogPositioning, tells ModalDialog how to position the dialog on the screen, as follows. dialogPositioning effect --------------------- ------------------------------------------------------------------------- "cardOffset" coordinates in DLOG resource are treated as local to the card "cardCenter" the dialog is centered over the card window "screenCenter" the dialog is centered on the main screen In addition, each of these options may be preceded by an "h" or a "v", with the following effects: "h" tells ModalDialog to alter only the horizontal positioning of the dialog, while "v" tells it to alter only the vertical positioning. For example, "hScreenCenter" will cause the dialog to be centered horizontally on the screen while retaining the vertical positioning specified in the DLOG resource. If there is no third parameter, or if it is something other than these options, the coordinates ModalDialog finds in the DLOG resource are treated as global coordinates and become the dialog's bounding rectangle. (Note: for compatibility with earlier versions, TRUE means the same thing as "cardOffset".) The fourth parameter, noCancel, tells ModalDialog whether or not there is a cancel item. If noCancel is TRUE, the user cannot dismiss the dialog by pressing command-period, command-Q, or the escape key, or by pressing any button other than the default item. If noCancel is not present, or if it is anything other than TRUE, then the cancel item is determined by the methods described above and the dialog can be cancelled. The fifth parameter, noWordWrap, tells ModalDialog whether or not you want automatic word wrapping in edit text items. If it is TRUE, there will be no word wrap. If it is absent or anything other than TRUE, the words will wrap. WHAT MODALDIALOG RETURNS If the user dismisses the dialog by clicking the default item or by pressing return or enter, ModalDialog returns a multi-line expression, one line per item in the dialog item list, describing what the dialog contained when it was dismissed. If the item is a check box or a radio button, the line corresponding to it will contain "off" if the button was off and "on" if the button was on. If the item is an edit text item, the line corresponding to it will contain the text of the item. If the item is any other type of dialog item, the line corresponding to it will be empty. If the user dismisses the dialog by clicking the cancel item or by pressing command-period, command-Q, or the escape key, then ModalDialog returns "Cancel". REVISION HISTORY March 15, 1989 -- 1.0 release. March 31, 1989 -- 1.0.1. Sped up scanning of input container. Container name should no longer be quoted. Default group for radio buttons is now 0, not 1. April 3, 1989 -- 1.0.2. Added pre-flight check for presence of DITL resource. Added more options for dialog positioning. June 25, 1989 -- 1.0.3. If user copies a selection from an edit text item in the dialog, the desk scrap will contain that text after the dialog is dismissed. -- part contents for card part 3 ----- text ----- UNIT ModalDialogUnit; { ModalDialog XCMD ©1989 by the Trustees of Dartmouth College } { Written by Kevin Calhoun } { This source compatible with MPW Pascal 3.0 } (* Pascal ModalDialog.p Link -m ENTRYPOINT ∂ -o "YourFile" ∂ -rt XFCN=13013 ∂ -sn Main=ModalDialog ∂ ModalDialog.p.o ∂ "{Libraries}"interface.o ∂ "{PLibraries}"Paslib.o ∂ "{Libraries}"HyperXLib.o *) {$R-} INTERFACE USES Types, Memory, Resources, Dialogs, Scrap, ToolUtils, OSUtils, Packages, Errors, HyperXCmd; PROCEDURE Entrypoint (paramPtr : XCmdPtr); IMPLEMENTATION CONST btnOn = 1; TYPE GlobalsHandle = ^GlobalsPtr; GlobalsPtr = ^GlobalsRecord; GlobalsRecord = RECORD dlogItems : INTEGER; wasDown : BOOLEAN; alteredScrap : BOOLEAN; defaultItem : INTEGER; cancelItem : INTEGER; selectedItem : INTEGER; editTextRgn : RgnHandle; arrowCursor, iBeamCurs : Cursor; END; WordHandle = ^WordPtr; WordPtr = ^INTEGER; PROCEDURE DoModalDlog (paramPtr : XCmdPtr); FORWARD; PROCEDURE Entrypoint (paramPtr: XCMDPtr); BEGIN DoModalDlog(paramPtr); END; FUNCTION GetScreenBitsBounds: Rect; TYPE LongwordPtr = ^LONGINT; BitMapPtr = ^BitMap; CONST screenBitsOffset = -122; CurrentA5 = $904; VAR screenBitsPtr : BitMapPtr; myLongwordPtr : LongwordPtr; BEGIN myLongwordPtr := LongwordPtr(CurrentA5); myLongwordPtr := LongwordPtr(myLongwordPtr^); screenBitsPtr := BitMapPtr(myLongwordPtr^ + screenBitsOffset); GetScreenBitsBounds := screenBitsPtr^.bounds; END; FUNCTION GetArrowCursor : Cursor; TYPE LongwordPtr = ^LONGINT; CONST arrowOffset = -108; CurrentA5 = $904; VAR arrowPtr : CursPtr; myLongwordPtr : LongwordPtr; BEGIN myLongwordPtr := LongwordPtr(CurrentA5); myLongwordPtr := LongwordPtr(myLongwordPtr^); arrowPtr := CursPtr(myLongwordPtr^ + arrowOffset); GetArrowCursor := arrowPtr^; END; PROCEDURE DrawBoxAroundDefault (theWindow : WindowPtr; itemNo : INTEGER); VAR itemType : integer; itemHdl : Handle; itemBox : rect; item : INTEGER; g : GlobalsHandle; ps : PenState; savePort : GrafPtr; BEGIN { If you steal this routine, get rid of the next three lines } { and figure out what the default item is some other way. } { Unless, of course, you use a handle to "globals" in the refCon } { field, just as I do. } g := GlobalsHandle(GetWRefCon(theWindow)); item := g^^.defaultItem; GetDItem(theWindow, item, itemType, itemHdl, itemBox); IF itemType = ctrlItem + btnCtrl THEN BEGIN GetPort(savePort); SetPort(theWindow); GetPenState(ps); PenSize(3, 3); InsetRect(itemBox, -4, -4); FrameRoundRect(itemBox, 16, 16); SetPenState(ps); SetPort(savePort); END; END; FUNCTION AddUserItem (d: DialogPtr; default: INTEGER) : OSErr; TYPE DItemPtr = ^dialogItem; DItemHndl = ^dItemPtr; DialogItem = RECORD placeholder : handle; displayRect : Rect; typeAndDataLength : INTEGER; END; VAR theUserItem : DItemHndl; itemType : INTEGER; itemHdl : Handle; itemBox : Rect; theItems : Handle; err : OSErr; BEGIN err := noErr; GetDItem(d, default, itemType, itemHdl, itemBox); IF itemType = ctrlItem + btnCtrl THEN BEGIN InsetRect(itemBox, -4, -4); theUserItem := DItemHndl(NewHandle(SIZEOF(DialogItem))); err := MemError; IF (theUserItem <> NIL) AND (err = noErr) THEN BEGIN MoveHHi(Handle(theUserItem)); HLock(Handle(theUserItem)); WITH theUserItem^^ DO BEGIN placeholder := Handle(@DrawBoxAroundDefault); displayRect := itemBox; typeAndDataLength := userItem * 256 + 0; END; theItems := DialogPeek(d)^.Items; err := HandAndHand(Handle(theUserItem), theItems); WordHandle(theItems)^^ := WordHandle(theItems)^^ + 1; DisposHandle(Handle(theUserItem)); END; END; AddUserItem := err; END; FUNCTION PtrToString (p: Ptr; size: byte): Str255; TYPE StrArray = PACKED ARRAY[0..255] of char; VAR s: Str255; BEGIN StrArray(s)[0] := CHR(size); BlockMove(p, Ptr(ORD4(@s) + 1), size); PtrToString := s; END; FUNCTION GetNextLine(paramPtr: XCMDPtr; var scanPtr: Ptr; var line: Str255) : BOOLEAN; VAR tempPtr : Ptr; temp : BOOLEAN; stringLength : LONGINT; BEGIN tempPtr := scanPtr; ScanToReturn(paramPtr, scanPtr); stringLength := ORD4(scanPtr)-ORD4(tempPtr); line := PtrToString(tempPtr, stringLength); GetNextLine := (scanPtr^ = 0); { advance our pointer beyond the CR, for the next time we're called } scanPtr := Ptr(ORD4(scanPtr)+1); END; FUNCTION GetNextItem(sPtr: StringPtr; var index: INTEGER; var item: Str255) : BOOLEAN; VAR start: INTEGER; sLength: INTEGER; BEGIN sLength := LENGTH(sPtr^); start := index; WHILE (sPtr^[index] <> ',') AND (index < sLength) DO index := index+1; IF index >= sLength THEN BEGIN GetNextItem := TRUE; IF sPtr^[sLength] = ',' THEN index:=index-1; item := COPY(sPtr^, start, (index-start+1)); index := sLength+1; END ELSE BEGIN GetNextItem := FALSE; item := COPY(sPtr^, start, (index-start)); index := index+1; END; END; PROCEDURE SetButtonItem(item: INTEGER; c: ControlHandle; desc: Str255); VAR lastItem : BOOLEAN; itemStr: Str255; g: GlobalsHandle; index: INTEGER; BEGIN index := 1; lastItem := GetNextItem(@desc, index, itemStr); g := GlobalsHandle(GetWRefCon(c^^.contrlOwner)); IF IUEqualString(itemStr, 'Default') = 0 THEN g^^.defaultItem := item ELSE IF IUEqualString(itemStr, 'Cancel') = 0 THEN g^^.cancelItem := item; IF NOT lastItem THEN BEGIN lastItem := GetNextItem(@desc, index, itemStr); IF LENGTH(itemStr) > 0 THEN SetCTitle(c, itemStr); END; END; PROCEDURE SetCheckBox(item: INTEGER; c: ControlHandle; desc: Str255); VAR lastItem: BOOLEAN; itemStr: Str255; index: INTEGER; BEGIN index := 1; lastItem := GetNextItem(@desc, index, itemStr); IF IUEqualString(itemStr, 'On') = 0 THEN SetCtlValue(c, btnOn); IF NOT lastItem THEN BEGIN lastItem := GetNextItem(@desc, index, itemStr); IF LENGTH(itemStr) > 0 THEN SetCTitle(c, itemStr); END; END; PROCEDURE SetRadioButton(paramPtr: XCMDPtr; item: INTEGER; c: ControlHandle; desc: Str255); VAR lastItem : BOOLEAN; itemStr: Str255; group: INTEGER; index: INTEGER; BEGIN index := 1; lastItem := GetNextItem(@desc, index, itemStr); IF IUEqualString(itemStr, 'On') = 0 THEN SetCtlValue(c, btnOn); IF NOT lastItem THEN BEGIN lastItem := GetNextItem(@desc, index, itemStr); IF LENGTH(itemStr) > 0 THEN BEGIN group := StrToNum(paramPtr, itemStr); SetCRefCon(c, group); END; IF NOT lastItem THEN BEGIN lastItem := GetNextItem(@desc, index, itemStr); IF LENGTH(itemStr) > 0 THEN SetCTitle(c, itemStr); END; END; END; PROCEDURE SetEditItem(d: DialogPtr; item: INTEGER; h: Handle; desc: Str255); VAR lastItem : BOOLEAN; itemStr: Str255; g: GlobalsHandle; index: INTEGER; BEGIN index := 1; lastItem := GetNextItem(@desc, index, itemStr); IF LENGTH(itemStr) > 0 THEN SetIText(h, itemStr); IF NOT lastItem THEN BEGIN lastItem := GetNextItem(@desc, index, itemStr); IF IUEqualString(itemStr, 'Select') = 0 THEN BEGIN g := GlobalsHandle(GetWRefCon(d)); g^^.selectedItem := item; END; END; END; PROCEDURE SetDialogItems(paramPtr: XCMDPtr; d: DialogPtr; dlogItems: INTEGER; inContainer: Handle); VAR hs: SignedByte; scanPtr: Ptr; i : INTEGER; str : Str255; lastLine : BOOLEAN; itemType : integer; itemHdl : Handle; itemBox : rect; BEGIN hs := HGetState(inContainer); HLock(inContainer); scanPtr := inContainer^; FOR i := 1 to dlogItems DO BEGIN GetDItem(d, i, itemType, itemHdl, itemBox); lastLine := GetNextLine(paramPtr, scanPtr, str); CASE itemType MOD itemDisable OF ctrlItem + btnCtrl: SetButtonItem(i, ControlHandle(itemHdl), str); ctrlItem + chkCtrl: SetCheckBox(i, ControlHandle(itemHdl), str); ctrlItem + radCtrl: SetRadioButton(paramPtr, i, ControlHandle(itemHdl), str); statText: IF LENGTH(str) > 0 THEN SetIText(itemHdl, str); editText: SetEditItem(d, i, itemHdl, str); END; { case itemType MOD itemDisable } IF lastLine then Leave; END; { for i := 1 to dlogItems } HSetState(inContainer, hs); END; FUNCTION ItemCount (theDialogPtr : DialogPtr) : integer; BEGIN ItemCount := WordHandle(DialogPeek(theDialogPtr)^.items)^^ + 1; END; FUNCTION GetLocOfCardWindow (cardWindow : WindowPtr) : Point; VAR savePort : GrafPtr; pt: Point; BEGIN GetPort(savePort); SetPort(cardWindow); WITH cardWindow^.portRect DO SetPt(pt,left,top); LocalToGlobal(pt); SetPort(savePort); GetLocOfCardWindow := pt; END; PROCEDURE MoveDialogRelativeToWindow (cardWindow: WindowPtr; doH, doV: BOOLEAN; theDialogTHndl : DialogTHndl); VAR tempRect : Rect; cardLoc : Point; BEGIN tempRect := theDialogTHndl^^.boundsRect; cardLoc := GetLocOfCardWindow(cardWindow); WITH cardLoc DO BEGIN {offset our DLOG rect according to loc of card window } IF NOT doH THEN h := 0; IF NOT doV THEN v := 0; OffSetRect(tempRect, h, v); END; theDialogTHndl^^.boundsRect := tempRect; { set DLOG boundsRect} END; PROCEDURE CenterRect(VAR r: Rect; inRect: Rect; doH, doV: BOOLEAN); VAR hSize, vSize: INTEGER; hCoord, vCoord: INTEGER; BEGIN WITH r DO BEGIN hCoord := left; vCoord := top; hSize := right-left; vSize := bottom-top; END; WITH inRect DO BEGIN IF doH THEN hCoord := (right-left - hSize) DIV 2 + left; IF doV THEN vCoord := (bottom-top - vSize) DIV 2 + top; END; SetRect(r, hCoord, vCoord, hCoord+hSize, vCoord+vSize); END; PROCEDURE CenterDialogOverWindow(cardWindow: WindowPtr; doH, doV: BOOLEAN; theDialogTHndl: DialogTHndl); VAR cardLoc : Point; windowRect: Rect; dlogRect: Rect; BEGIN cardLoc := GetLocOfCardWindow(cardWindow); windowRect := cardWindow^.portRect; WITH windowRect DO OffsetRect(windowRect, -left, -top); WITH cardLoc DO OffsetRect(windowRect, h, v); dlogRect := theDialogTHndl^^.boundsRect; CenterRect(dlogRect, windowRect, doH, doV); theDialogTHndl^^.boundsRect := dlogRect; END; PROCEDURE CenterDialogOverScreen(doH, doV: BOOLEAN; theDialogTHndl: DialogTHndl); VAR screenRect: Rect; dlogRect: Rect; BEGIN dlogRect := theDialogTHndl^^.boundsRect; screenRect := GetScreenBitsBounds; CenterRect(dlogRect, screenRect, doH, doV); theDialogTHndl^^.boundsRect := dlogRect; END; FUNCTION SetUpGlobals (theDialog : DialogPtr) : OSErr; LABEL 99; VAR err : OSErr; numItems, i : INTEGER; g : GlobalsHandle; tempRgn : RgnHandle; itemType : INTEGER; ItemHdl : Handle; itemBox : rect; iBeam : CursHandle; gotDefault, gotCancel, gotSelectedItem: BOOLEAN; BEGIN err := noErr; g := GlobalsHandle(NewHandle(SizeOf(GlobalsRecord))); err := MemError; IF (err <> noErr) or (g = NIL) then GOTO 99; numItems := ItemCount(theDialog); WITH g^^ DO BEGIN dlogItems := numItems; wasDown := FALSE; alteredScrap := FALSE; END; gotDefault := FALSE; gotCancel := FALSE; gotSelectedItem := FALSE; tempRgn := NewRgn; OpenRgn; FOR i := 1 TO numItems DO BEGIN GetDItem(theDialog, i, itemType, itemHdl, itemBox); CASE itemType OF editText, editText+itemDisable: BEGIN FrameRect(itemBox); IF not gotSelectedItem THEN BEGIN g^^.selectedItem := i; gotSelectedItem := TRUE; END; END; ctrlItem + btnCtrl: IF not gotDefault THEN BEGIN g^^.defaultItem := i; gotDefault := TRUE; END ELSE IF not gotCancel THEN BEGIN g^^.cancelItem := i; gotCancel := TRUE; END; END; END; CloseRgn(tempRgn); err := MemError; IF err <> noErr THEN BEGIN DisposHandle(Handle(g)); GOTO 99; END; IF not gotDefault THEN g^^.defaultItem := OK; IF not gotCancel THEN g^^.cancelItem := Cancel; IF not gotSelectedItem THEN g^^.selectedItem := 0; g^^.editTextRgn := tempRgn; iBeam := GetCursor(iBeamCursor); g^^.iBeamCurs := iBeam^^; g^^.arrowCursor := GetArrowCursor; SetWRefCon(theDialog,LONGINT(g)); 99: SetUpGlobals := err; END; PROCEDURE DisposeGlobals (theDialog : DialogPtr); VAR g : GlobalsHandle; rgn : RgnHandle; BEGIN g := GlobalsHandle(GetWRefCon(theDialog)); rgn := g^^.editTextRgn; DisposeRgn(rgn); DisposHandle(Handle(g)); END; FUNCTION TheFilter (theDialog : DialogPtr; VAR theEvent : EventRecord; VAR itemHit : integer) : boolean; VAR mouseLoc : Point; theItem : INTEGER; numItems : INTEGER; g : GlobalsHandle; curs : Cursor; theChar : INTEGER; FUNCTION SelectionNotEmpty(dlg: DialogPtr): BOOLEAN; VAR te: TEHandle; BEGIN SelectionNotEmpty := FALSE; IF DialogPeek(dlg)^.editField > -1 THEN WITH DialogPeek(dlg)^.textH^^ DO SelectionNotEmpty := selEnd > selStart; END; PROCEDURE PushButton (itemNo : INTEGER); VAR itemType : INTEGER; itemHandle : Handle; itemBox : Rect; finalTicks : longint; BEGIN GetDItem(theDialog, itemNo, itemType, itemHandle, itemBox); IF itemType = ctrlItem + btnCtrl THEN BEGIN HiliteControl(ControlHandle(itemHandle), btnOn); Delay(3, finalTicks); HiliteControl(ControlHandle(itemHandle), 0); END; END; PROCEDURE PrevEditField(dlg: DialogPtr); VAR numItems: INTEGER; theEditItem: INTEGER; itemType: INTEGER; itemHandle: Handle; itemBox: Rect; BEGIN numItems := ItemCount(dlg); IF numItems > 0 THEN BEGIN theEditItem := DialogPeek(dlg)^.editField + 1; if theEditItem > 0 then BEGIN REPEAT theEditItem := (theEditItem + numItems - 2) MOD numItems + 1; GetDItem(dlg, theEditItem, itemType, itemHandle, itemBox); UNTIL (itemType mod itemDisable = editText); SelIText(dlg, theEditItem, 0, 32767); END; END; END; BEGIN g := GlobalsHandle(GetWRefCon(theDialog)); itemHit := 0; TheFilter := false; numItems := g^^.dlogItems; IF g^^.wasDown AND NOT StillDown THEN BEGIN ObscureCursor; g^^.wasDown := false; END; mouseLoc := theEvent.where; GlobalToLocal(mouseLoc); CASE theEvent.what OF nullEvent,updateEvt : BEGIN IF PtInRgn(mouseLoc, g^^.editTextRgn) THEN curs := g^^.iBeamCurs ELSE curs := g^^.arrowCursor; SetCursor(curs); END; mouseDown : WITH g^^ DO IF PtInRgn(mouseLoc, editTextRgn) THEN wasDown := true; keyDown, autoKey : BEGIN theChar := BitAnd(theEvent.message, charCodeMask); CASE theChar OF $2E, $71, $51: { command-., -q, or -Q } BEGIN IF BitAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN theItem := g^^.cancelItem; IF theItem > 0 THEN BEGIN PushButton(theItem); itemHit := theItem; TheFilter := TRUE; END; END; END; $78,$58: { x, X } IF BitAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN g^^.alteredScrap := g^^.alteredScrap OR SelectionNotEmpty(theDialog); TheFilter := TRUE; DlgCut(theDialog); END; $63, $43: { c, C } IF BitAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN g^^.alteredScrap := g^^.alteredScrap OR SelectionNotEmpty(theDialog); TheFilter := TRUE; DlgCopy(theDialog); END; $76, $56: { v, V } IF BitAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN TheFilter := TRUE; DlgPaste(theDialog); END; $09: { tab key } IF BitAnd(theEvent.modifiers, shiftKey) <> 0 THEN BEGIN TheFilter := TRUE; PrevEditField(theDialog); END; $0D, $03: { Return or Enter } BEGIN theItem := g^^.defaultItem; IF theItem > 0 THEN BEGIN PushButton(theItem); TheFilter := true; itemHit := theItem; END; END; $1B : { escape key } BEGIN theItem := g^^.cancelItem; IF theItem > 0 THEN BEGIN PushButton(theItem); itemHit := theItem; TheFilter := TRUE; END; END; OTHERWISE ObscureCursor; END; { case theChar } END; { keyDown } END; {case theEvent.what} END; {function TheFilter} PROCEDURE DoCheckBox(c: ControlHandle); VAR controlValue : INTEGER; BEGIN controlValue := GetCtlValue(c); controlValue := (controlValue + 1) MOD 2; SetCtlValue(c, controlValue); END; PROCEDURE DoRadioButtons(d: DialogPtr; item: INTEGER; c: ControlHandle); VAR controlValue : INTEGER; group : INTEGER; numItems : INTEGER; i : INTEGER; itemType : INTEGER; itemHdl : Handle; itemBox : Rect; BEGIN controlValue := GetCtlValue(c); IF controlValue = 0 THEN BEGIN group := LoWord(GetCRefCon(c)); numItems := ItemCount(d); FOR i := 1 to numItems DO BEGIN GetDItem(d, i, itemType, itemHdl, itemBox); IF itemType = ctrlItem + radCtrl THEN BEGIN IF LoWord(GetCRefCon(ControlHandle(itemHdl))) = group THEN SetCtlValue(ControlHandle(itemHdl), 0); END; END; SetCtlValue(c, 1); END; END; FUNCTION AppendString (h: Handle; str: Str255): OSErr; BEGIN AppendString := PtrAndHand(POINTER(ORD4(@str)+1), h, LENGTH(str)); END; FUNCTION SpewOutResults(paramPtr: XCMDPtr; d: DialogPtr; numItems: INTEGER; var h: Handle): OSErr; LABEL 99; VAR err: OSErr; str: Str255; i: INTEGER; itemType: INTEGER; itemHdl: Handle; itemBox: Rect; return: String[1]; controlValue: INTEGER; zeroPtr: Ptr; PROCEDURE SetReturnValue; BEGIN SpewOutResults := err; END; PROCEDURE GetOut; BEGIN DisposHandle(h); SetReturnValue; EXIT(SpewOutResults); END; BEGIN err := noErr; return := ' '; return[1] := CHR($0D); FOR i := 1 to numItems DO BEGIN GetDItem(d, i, itemType, itemHdl, itemBox); CASE itemType MOD itemDisable OF ctrlItem + chkCtrl, ctrlItem + radCtrl: BEGIN controlValue := GetCtlValue(ControlHandle(itemHdl)); IF controlValue = btnOn THEN str := CONCAT('on', return) ELSE str := CONCAT('off', return); err := AppendString(h, str); IF err <> noErr THEN GetOut; END; editText: BEGIN GetIText(itemHdl, str); str := CONCAT(str, return); err := AppendString(h, str); IF err <> noErr THEN GetOut; END; OTHERWISE BEGIN err := AppendString(h, return); IF err <> noErr THEN GetOut; END; END; END; HLock(h); zeroPtr := POINTER(ORD4(h^)+GetHandleSize(h)-1); zeroPtr^ := 0; HUnlock(h); 99: SetReturnValue; END; PROCEDURE DoModalDlog (paramPtr : XCmdPtr); LABEL 98, 99; CONST noWrap = -1; VAR dlogName : Str255; inContainer : Handle; str : Str255; {Resource related variables} theResource, theDITL : Handle; theId, ditlID : INTEGER; theType : ResType; {Dialog related variables} numItems : INTEGER; myDialogTHndl : DialogTHndl; myDialogPtr : DialogPtr; dlogRect : Rect; {Dialog item related variables} itemType : INTEGER; ItemHdl : Handle; itemBox : rect; i, itemHit, def : INTEGER; g : GlobalsHandle; h : Handle; movedIt : BOOLEAN; hOrV : Char; doH, doV: BOOLEAN; cardWindow: WindowPtr; scrapErr: LONGINT; err : OSErr; PROCEDURE PassReturnValue (errMsg : Str255); { set theResult } BEGIN paramPtr^.returnValue := PasToZero(paramPtr, errMsg); END; BEGIN err := noErr; IF paramPtr^.paramCount = 0 THEN BEGIN PassReturnValue('ModalDialog XFCN 1.0.3, 25 June 1989, ©1989 Dartmouth College'); GOTO 99; END; GetPort(GrafPtr(cardWindow)); { get card window WindowPtr } ZeroToPas(paramPtr, paramPtr^.params[1]^, dlogName); IF LENGTH(dlogName) = 0 THEN GOTO 99; theResource := GetNamedResource('DLOG', dlogName); err := ResError; IF (theResource = NIL) OR (err <> noErr) THEN GOTO 99; IF paramPtr^.paramCount > 1 THEN inContainer := paramPtr^.params[2] ELSE inContainer := NIL; HNoPurge(theResource); GetResInfo(theResource, theID, theType, dlogName); err := ResError; IF err <> noErr THEN GOTO 99; myDialogTHndl := DialogTHndl(theResource); ditlID := myDialogTHndl^^.itemsID; theDITL := GetResource('DITL',ditlID); IF theDITL = NIL THEN BEGIN err := resNotFound; GOTO 99; END; movedIt := FALSE; myDialogTHndl^^.visible := FALSE; IF paramPtr^.paramCount > 2 THEN BEGIN dlogRect := myDialogTHndl^^.boundsRect; ZeroToPas(paramPtr, paramPtr^.params[3]^, str); hOrV := str[1]; doH := TRUE; doV := TRUE; CASE hOrV OF 'h','H': BEGIN doV := FALSE; DELETE(str, 1, 1); END; 'v','V': BEGIN doH := FALSE; DELETE(str, 1, 1); END; END; IF (IUEqualString(str, 'true')=0) OR (IUEqualString(str, 'cardOffset')=0) THEN BEGIN movedIt := TRUE; MoveDialogRelativeToWindow(cardWindow, doH, doV, myDialogTHndl); END ELSE IF IUEqualString(str, 'cardCenter') = 0 THEN BEGIN movedIt := TRUE; CenterDialogOverWindow(cardWindow, doH, doV, myDialogTHndl); END ELSE IF IUEqualString(str, 'screenCenter') = 0 THEN BEGIN movedIt := TRUE; CenterDialogOverScreen(doH, doV, myDialogTHndl); END; END; myDialogPtr := GetNewDialog(theID, NIL, POINTER(-1)); numItems := ItemCount(myDialogPtr); err := SetUpGlobals(myDialogPtr); IF err <> noErr THEN GOTO 98; IF paramPtr^.paramCount > 4 THEN BEGIN ZeroToPas(paramPtr, paramPtr^.params[5]^, str); IF StrToBool(paramPtr, str) THEN DialogPeek(myDialogPtr)^.textH^^.crOnly := noWrap; { turn off word wrap } END; IF inContainer <> NIL THEN SetDialogItems(paramPtr, myDialogPtr, numItems, inContainer); g := GlobalsHandle(GetWRefCon(myDialogPtr)); def := g^^.defaultItem; err := AddUserItem(myDialogPtr, def); IF err <> noErr THEN BEGIN DisposeGlobals(myDialogPtr); GOTO 98; END; IF g^^.selectedItem > 0 THEN SelIText(myDialogPtr,g^^.selectedItem,0,32767); IF paramPtr^.paramCount > 3 THEN BEGIN ZeroToPas(paramPtr, paramPtr^.params[4]^, str); IF StrToBool(paramPtr, str) THEN g^^.cancelItem := 0; END; ShowWindow(myDialogPtr); { make DLOG visible } BringToFront(myDialogPtr); SetPort(myDialogPtr); InitCursor; REPEAT ModalDialog(@TheFilter, itemHit); GetDItem(myDialogPtr, itemHit, itemType, itemHdl, itemBox); CASE itemType OF ctrlItem + chkCtrl: DoCheckBox(ControlHandle(itemHdl)); ctrlItem + radCtrl: DoRadioButtons(myDialogPtr, itemHit, ControlHandle(itemHdl)); END; UNTIL (itemHit = def) OR (itemHit = g^^.cancelItem); IF g^^.alteredScrap THEN BEGIN scrapErr := ZeroScrap; scrapErr := TEToScrap; END; DisposeGlobals(myDialogPtr); IF itemHit = def THEN BEGIN h := NewHandle(0); err := MemError; IF err <> noErr THEN GOTO 98; err := SpewOutResults(paramPtr, myDialogPtr, numItems, h); IF err <> noErr THEN GOTO 98; paramPtr^.returnValue := h; END ELSE PassReturnValue('Cancel'); {set rect of DLOG to original rectangle} 98: IF movedIt THEN myDialogTHndl^^.boundsRect := dlogRect; { reset DLOG boundsRect} HPurge(theResource); DisposDialog(myDialogPtr); 99: IF err <> noErr THEN BEGIN NumToStr(paramPtr, err, str); PassReturnValue(CONCAT('Error ', str)); END; END; {procedure DoModalDlog} END.